package org.mparts.client.ui;

import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;

import org.mparts.client.content.Images;
import org.mparts.client.content.Strings;
import org.mparts.client.utils.Utils;
import org.mparts.shared.MpartsRequestFactory;
import org.mparts.shared.proxy.AutoProxy;
import org.mparts.shared.proxy.EngineProxy;
import org.mparts.shared.proxy.PartgroupProxy;
import org.mparts.shared.proxy.PartitemProxy;
import org.mparts.shared.request.MpartsRequest;

import com.allen_sauer.gwt.log.client.Log;
import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.editor.client.Editor.Ignore;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiFactory;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.ResizeComposite;
import com.google.gwt.user.client.ui.Widget;
import com.google.inject.Inject;
import com.google.web.bindery.event.shared.EventBus;
import com.google.web.bindery.requestfactory.shared.Receiver;
import com.sencha.gxt.data.shared.ListStore;
import com.sencha.gxt.data.shared.SortInfo;
import com.sencha.gxt.data.shared.StringLabelProvider;
import com.sencha.gxt.data.shared.loader.FilterConfig;
import com.sencha.gxt.data.shared.loader.FilterConfigBean;
import com.sencha.gxt.data.shared.loader.FilterPagingLoadConfig;
import com.sencha.gxt.data.shared.loader.FilterPagingLoadConfigBean;
import com.sencha.gxt.data.shared.loader.LoadResultListStoreBinding;
import com.sencha.gxt.data.shared.loader.PagingLoadResult;
import com.sencha.gxt.data.shared.loader.PagingLoader;
import com.sencha.gxt.data.shared.loader.RequestFactoryProxy;
import com.sencha.gxt.widget.core.client.ContentPanel;
import com.sencha.gxt.widget.core.client.button.TextButton;
import com.sencha.gxt.widget.core.client.event.SelectEvent;
import com.sencha.gxt.widget.core.client.event.SelectEvent.HasSelectHandlers;
import com.sencha.gxt.widget.core.client.form.ComboBox;
import com.sencha.gxt.widget.core.client.form.NumberPropertyEditor;
import com.sencha.gxt.widget.core.client.form.SimpleComboBox;
import com.sencha.gxt.widget.core.client.grid.ColumnConfig;
import com.sencha.gxt.widget.core.client.grid.ColumnModel;
import com.sencha.gxt.widget.core.client.grid.Grid;
import com.sencha.gxt.widget.core.client.grid.GroupingView;
import com.sencha.gxt.widget.core.client.grid.filters.GridFilters;
import com.sencha.gxt.widget.core.client.grid.filters.NumericFilter;
import com.sencha.gxt.widget.core.client.grid.filters.StringFilter;
import com.sencha.gxt.widget.core.client.selection.SelectionChangedEvent;
import com.sencha.gxt.widget.core.client.selection.SelectionChangedEvent.SelectionChangedHandler;
import com.sencha.gxt.widget.core.client.toolbar.PagingToolBar;
import com.sencha.gxt.widget.core.client.toolbar.ToolBar;

public class CatalogView extends ResizeComposite implements IsWidget, ICatalogView {
	
	public interface Binder extends UiBinder<Widget, CatalogView> {
	}

	private static final PartitemProxyProperties propsPartitem = GWT
			.create(PartitemProxyProperties.class);
	private static final AutoProxyProperties propsAuto = GWT
			.create(AutoProxyProperties.class);
	private static final PartgroupProxyProperties propsGrp = GWT
			.create(PartgroupProxyProperties.class);
	private static final EngineProxyProperties propsEngine = GWT
			.create(EngineProxyProperties.class);

	private static final NumberFormat number = NumberFormat.getCurrencyFormat();// getFormat("0.00");

	protected ColumnConfig<PartitemProxy, String> codeColumn;
	protected ColumnConfig<PartitemProxy, String> nameColumn;
	protected ColumnConfig<PartitemProxy, Integer> priceColumn;
	protected ColumnConfig<PartitemProxy, String> autoColumn;
	protected ColumnConfig<PartitemProxy, String> modelColumn;
	protected ColumnConfig<PartitemProxy, String> vinColumn;
	protected ColumnConfig<PartitemProxy, String> numColumn;
	protected ColumnConfig<PartitemProxy, String> engineColumn;
	protected ColumnConfig<PartitemProxy, String> colorColumn;
	protected ColumnConfig<PartitemProxy, String> mandateColumn;
	protected ColumnConfig<PartitemProxy, String> noteColumn;
	protected ColumnConfig<PartitemProxy, String> driveColumn;
	protected RequestFactoryProxy<FilterPagingLoadConfig, PagingLoadResult<PartitemProxy>> proxy;
	protected PagingLoader<FilterPagingLoadConfig, PagingLoadResult<PartitemProxy>> loader;
	protected MpartsRequestFactory rf;
	protected Grid<PartitemProxy> grid;

	// protected 
	@UiField
	ContentPanel panel;
	
//	protected VerticalLayoutContainer container;

	private ICatalogPresenter presenter;

	private Strings strings;
	private Images images;

	protected ListStore<PartitemProxy> store = new ListStore<PartitemProxy>(propsPartitem.key());
	private ListStore<PartgroupProxy> grpStore = new ListStore<PartgroupProxy>(propsGrp.key());
	private ListStore<AutoProxy> autoStore = new ListStore<AutoProxy>(propsAuto.key());
	private ListStore<EngineProxy> engineStore = new ListStore<EngineProxy>(propsEngine.key());

	private String searchCriteria = "";
//	private ComboBox<AutoProxy> searchAuto;
//	private ComboBox<PartgroupProxy> searchGrp;

	@UiField(provided = true)
	@Ignore
	ComboBox<PartgroupProxy> searchGrp = new ComboBox<PartgroupProxy>(grpStore,
			propsGrp.name());

	@UiField(provided = true)
	@Ignore
	ComboBox<AutoProxy> searchAuto = new ComboBox<AutoProxy>(autoStore,
			propsAuto.name());
	
//	@UiField(provided = true)
//	@Ignore
//	ComboBox<EngineProxy> searchEngine2 = new ComboBox<EngineProxy>(engineStore,
//			propsEngine.name());
	
	@UiField(provided = true)
	@Ignore
	SimpleComboBox<String> searchEngine = new SimpleComboBox<String>(new StringLabelProvider<String>()) {

		@Override
		protected void onBlur(Event be) {
			String value = getCell().getText(getElement());
			super.onBlur(be);
//			setValue(value);  //закомментарим пока есть выбор из списка
		}
		
	};
	
	@UiField
	TextButton searchButton;
	
	@UiField
	PagingToolBar toolBar;
	
	@UiField
	ToolBar actionToolBar;
	
	@UiField
	TextButton addButton;
	
	@UiField
	TextButton editButton;

	@UiField
	TextButton deleteButton;
//	private IPartitemEditorView editor;
	
//	@UiField
//	VerticalLayoutContainer vCnt;
	
	private EventBus eventBus;
	
	private Widget root;

	@Inject
	public CatalogView(Images images, Strings strings, MpartsRequestFactory rf, EventBus eventBus, Binder uiBinder) {
		Log.debug("create CatalogView...");
		this.rf = rf;
		this.strings = strings;
		this.images = images;
		this.eventBus = eventBus;
		
		createProxy();
		createLoader();
		root = uiBinder.createAndBindUi(this);

		addManagerUI();
		addToolBar();
		
		addHandlers();
		
	}

	private void addHandlers() {
		searchGrp.addSelectionHandler(new SelectionHandler<PartgroupProxy>() {
			
			@Override
			public void onSelection(SelectionEvent<PartgroupProxy> event) {
				filterEngines(event.getSelectedItem(), searchAuto.getValue());
			}
		});
		
		searchGrp.addValueChangeHandler(new ValueChangeHandler<PartgroupProxy>() {
			
			@Override
			public void onValueChange(ValueChangeEvent<PartgroupProxy> event) {
				filterEngines(event.getValue(), searchAuto.getValue());				
			}
		});
		
		searchAuto.addSelectionHandler(new SelectionHandler<AutoProxy>() {
			
			@Override
			public void onSelection(SelectionEvent<AutoProxy> event) {
				filterEngines(searchGrp.getValue(), event.getSelectedItem());				
			}
		});
		
		searchAuto.addValueChangeHandler(new ValueChangeHandler<AutoProxy>() {
			
			@Override
			public void onValueChange(ValueChangeEvent<AutoProxy> event) {
				filterEngines(searchGrp.getValue(), event.getValue());				
			}
		});
		
	}

	/**
	 * 
	 */
	protected void addManagerUI() {
		if (Utils.isManager()) {
			actionToolBar.setVisible(true);
			actionToolBar.getElement().getStyle().setProperty("borderBottom", "none");
			grid.getSelectionModel().addSelectionChangedHandler(
					new SelectionChangedHandler<PartitemProxy>() {

						@Override
						public void onSelectionChanged(
								SelectionChangedEvent<PartitemProxy> event) {
							int size = event.getSelection().size();
							if (size == 0) {
								editButton.setEnabled(false);
								deleteButton.setEnabled(false);
							} else if (size == 1) {
								editButton.setEnabled(true);
								deleteButton.setEnabled(true);
							} else if (size > 1) {
								editButton.setEnabled(false);
								deleteButton.setEnabled(true);
							}

						}
					});
//			editor = new PartitemEditor(rf, eventBus);
		}
		
//		container.add(grid, new VerticalLayoutData(1, 1));
	}

	/**
	 * 
	 */
	protected String getPanelHeading() {
		return strings.catalog();
	}

	@UiFactory
	Grid<PartitemProxy> createGrid() {
		Log.debug("create grid...");
		List<ColumnConfig<PartitemProxy, ?>> l = getColumnConfigList();

		ColumnModel<PartitemProxy> cm = new ColumnModel<PartitemProxy>(l);

		grid = new Grid<PartitemProxy>(store, cm) {
			@Override
			protected void onAfterFirstAttach() {
				super.onAfterFirstAttach();
				Scheduler.get().scheduleDeferred(new ScheduledCommand() {
					@Override
					public void execute() {
						loader.load();
					}
				});
			}
		};
		// setGridGrouping();
		grid.getView().setForceFit(true);
		grid.getView().setAutoFill(true);
		grid.setLoadMask(true);
		grid.setLoader(loader);
//		grid.setVisible(false);
		grid.setBorders(true);

		setGridFilters();
		
		return grid;
	}

	protected void addToolBar() {
//		toolBar = new PagingToolBar(50);
		toolBar.getElement().getStyle().setProperty("borderBottom", "none");
//		toolBar.setVisible(false);
		toolBar.bind(loader);
//		container.add(toolBar, new VerticalLayoutData(1, -1));
	}

	/**
	 * 
	 */
	protected void setGridGrouping() {
		final GroupingView<PartitemProxy> gridView = new GroupingView<PartitemProxy>();
		gridView.setShowGroupedColumn(false);
		// gridView.setForceFit(true);
		// gridView.setStartCollapsed(true);

		grid.setView(gridView);
		gridView.groupBy(nameColumn);
	}

	/**
	 * @param grid
	 */
	protected void setGridFilters() {
		GridFilters<PartitemProxy> filters = new GridFilters<PartitemProxy>(
				loader);
		filters.initPlugin(grid);
		filters.setLocal(false);
		// filters.addFilter(new
		// StringFilter<PartitemProxy>(propsPartitem.code()));
		filters.addFilter(new StringFilter<PartitemProxy>(propsPartitem
				.grpName()));
		filters.addFilter(new StringFilter<PartitemProxy>(propsPartitem
				.autoName()));
		filters.addFilter(new StringFilter<PartitemProxy>(propsPartitem
				.modelName()));
		filters.addFilter(new NumericFilter<PartitemProxy, Integer>(
				propsPartitem.price(),
				new NumberPropertyEditor.IntegerPropertyEditor(number)));
	}

//	protected void createStore() {
//		store = new ListStore<PartitemProxy>(propsPartitem.key());
//	}

	/**
	 * Store have to be not null
	 */
	protected void createLoader() {
		// loader = new ListLoader<ListLoadConfig,
		// ListLoadResult<PartitemProxy>>(proxy);
		loader = new PagingLoader<FilterPagingLoadConfig, PagingLoadResult<PartitemProxy>>(
				proxy) {
			@Override
			protected FilterPagingLoadConfig newLoadConfig() {
				return new FilterPagingLoadConfigBean();
			}
		};
		loader.setRemoteSort(true);
		// loader.addLoadHandler(new LoadResultListStoreBinding<ListLoadConfig,
		// PartitemProxy, ListLoadResult<PartitemProxy>>(store));
		loader.addLoadHandler(new LoadResultListStoreBinding<FilterPagingLoadConfig, PartitemProxy, PagingLoadResult<PartitemProxy>>(
				store));

	}

	protected void createProxy() {
		// proxy = new RequestFactoryProxy<ListLoadConfig,
		// ListLoadResult<PartitemProxy>>() {
		// @Override
		// public void load(ListLoadConfig loadConfig, Receiver<? super
		// ListLoadResult<PartitemProxy>> receiver) {
		// MpartsRequest req = rf.mpartsRequest();
		// req.partitemList().to(receiver);
		// // List<SortInfo> sortInfo = createRequestSortInfo(req,
		// loadConfig.getSortInfo());
		// // List<FilterConfig> filterConfig = createRequestFilterConfig(req,
		// loadConfig.getFilters());
		// // req.getPosts(loadConfig.getOffset(), loadConfig.getLimit(),
		// sortInfo, filterConfig).to(receiver);
		//
		// req.fire();
		// }
		// };

		proxy = new RequestFactoryProxy<FilterPagingLoadConfig, PagingLoadResult<PartitemProxy>>() {
			@Override
			public void load(FilterPagingLoadConfig loadConfig,
					Receiver<? super PagingLoadResult<PartitemProxy>> receiver) {
				if (grid.isVisible()) {
					MpartsRequest req = rf.mpartsRequest();
					List<SortInfo> sortInfo = createRequestSortInfo(req,
							loadConfig.getSortInfo());
					List<FilterConfig> filters = new ArrayList<FilterConfig>();
					filters.addAll(loadConfig.getFilters());
					if (searchCriteria != null && searchCriteria.length() > 0) {
						Log.debug("add search criteria: " + searchCriteria);
						FilterConfigBean bean = new FilterConfigBean();
						bean.setComparison("wide");
						bean.setField("autoName:modelName:grpName:note:drive:engine");
						bean.setValue(searchCriteria);
						filters.add(bean);
					}
					if (searchAuto.getValue() != null) {
						Log.debug("add search by auto: "
								+ searchAuto.getValue().getId().toString()
								+ "[" + searchAuto.getValue().getName() + "]");
						FilterConfigBean bean = new FilterConfigBean();
						bean.setComparison("eq");
						bean.setField("auto");
						bean.setValue(searchAuto.getValue().getId().toString());
						filters.add(bean);
					}
					if (searchGrp.getValue() != null) {
						Log.debug("add search by group: "
								+ searchGrp.getValue().getId().toString() + "["
								+ searchGrp.getValue().getName() + "]");
						FilterConfigBean bean = new FilterConfigBean();
						bean.setComparison("eq");
						bean.setField("grp");
						bean.setValue(searchGrp.getValue().getId().toString());
						filters.add(bean);
					}
					if (searchEngine.getText() != null && searchEngine.getText().length() > 0) {
						Log.debug("add search by engine: "
								+ searchEngine.getText());
						FilterConfigBean bean = new FilterConfigBean();
						bean.setComparison("contains");
						bean.setField("engine");
						bean.setValue(searchEngine.getText());
						filters.add(bean);
					}
					//add storage filter
					Log.debug("add search by store: "
							+ Utils.getCurrentStoreId());
					FilterConfigBean bean = new FilterConfigBean();
					bean.setComparison("eq");
					bean.setField("storeId");
					bean.setValue(Utils.getCurrentStoreId().toString());
					filters.add(bean);
					//
					List<FilterConfig> filterConfig = createRequestFilterConfig(
							req, filters);
					req.partitemList(loadConfig.getOffset(),
							loadConfig.getLimit(), sortInfo, filterConfig).to(
							receiver);

					req.fire();
				}
			}
		};

	}

	protected ArrayList<ColumnConfig<PartitemProxy, ?>> getColumnConfigList() {
		codeColumn = new ColumnConfig<PartitemProxy, String>(
				propsPartitem.code(), 100, Utils.getStrings().partitemCode());
		nameColumn = new ColumnConfig<PartitemProxy, String>(
				propsPartitem.grpName(), 150, Utils.getStrings()
						.partitemGrpName());
		priceColumn = new ColumnConfig<PartitemProxy, Integer>(
				propsPartitem.price(), 100, Utils.getStrings().partitemPrice());
		priceColumn.setAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
		priceColumn.setCell(new AbstractCell<Integer>() {

			@Override
			public void render(Context context, Integer value,
					SafeHtmlBuilder sb) {
				// String style = "style='color: " + (value < 0 ? "red" :
				// "green") + "'";
				String v = number.format(value);
				sb.appendHtmlConstant(v);
			}
		});
		autoColumn = new ColumnConfig<PartitemProxy, String>(
				propsPartitem.autoName(), 100, strings.partitemAuto());
		modelColumn = new ColumnConfig<PartitemProxy, String>(
				propsPartitem.modelName(), 100, strings.partitemModel());
		numColumn = new ColumnConfig<PartitemProxy, String>(
				propsPartitem.num(), 100, strings.partitemNum());
		engineColumn = new ColumnConfig<PartitemProxy, String>(
				propsPartitem.engine(), 80, strings.partitemEngine());
		driveColumn = new ColumnConfig<PartitemProxy, String>(
				propsPartitem.drive(), 70, strings.partitemDrive());
		mandateColumn = new ColumnConfig<PartitemProxy, String>(
				propsPartitem.manDate(), 100, strings.partitemManDate());
		noteColumn = new ColumnConfig<PartitemProxy, String>(
				propsPartitem.note(), 200, strings.partitemNote());

		ArrayList<ColumnConfig<PartitemProxy, ?>> l = new ArrayList<ColumnConfig<PartitemProxy, ?>>();

		addColumns2Config(l);

		return l;
	}

	protected void addColumns2Config(ArrayList<ColumnConfig<PartitemProxy, ?>> l) {
		// l.add(codeColumn);
		l.add(nameColumn);
		l.add(autoColumn);
		l.add(modelColumn);
		// l.add(vinColumn);
//		l.add(mandateColumn);
//		l.add(numColumn);
		l.add(engineColumn);
		l.add(driveColumn);
		l.add(noteColumn);
		l.add(priceColumn);
	}

	@Override
	public void setSearchCriteria(String criteria) {
		searchCriteria = criteria;
		if ( searchCriteria != null && searchCriteria.length() >0 ) {
			searchAuto.clear();
			searchGrp.clear();
			loader.load();
		}
	}

	@Override
	public void setPresenter(ICatalogPresenter presenter) {
		this.presenter = presenter;
//		presenter.initEditorActivity(editor);
		if (grpStore.size() == 0 || autoStore.size() == 0) {
			grpStore.clear();
			autoStore.clear();
			engineStore.clear();
			presenter.loadLists(grpStore, autoStore, searchEngine.getStore());
		}

	}

//	protected FieldSet getSearchPanel() {
//
//		FieldSet searchArea = new FieldSet();
//		searchArea.setCollapsible(true);
//		searchArea.setHeight(60);
//		searchArea.setHeadingText(strings.catalogSearchTitle());
//		HorizontalLayoutContainer cont = new HorizontalLayoutContainer();
//		searchArea.add(cont);
//
////		grpStore = new ListStore<PartgroupProxy>(propsGrp.key());
//		searchGrp = new ComboBox<PartgroupProxy>(grpStore, propsGrp.name());
//		searchGrp.setTypeAhead(false);
//		searchGrp.setTriggerAction(TriggerAction.ALL);
//		searchGrp.setWidth(200);
//		FieldLabel grpLabel = new FieldLabel(searchGrp,
//				strings.catalogSearchType());
//		grpLabel.setLabelWidth(80);
//		cont.add(grpLabel);
//
////		autoStore = new ListStore<AutoProxy>(propsAuto.key());
//		searchAuto = new ComboBox<AutoProxy>(autoStore, propsAuto.name());
//		searchAuto.setTypeAhead(false);
//		searchAuto.setTriggerAction(TriggerAction.ALL);
//		searchAuto.setWidth(150);
//		FieldLabel autoLabel = new FieldLabel(searchAuto,
//				strings.partitemAuto());
//		autoLabel.setLabelWidth(40);
//		cont.add(autoLabel, new HorizontalLayoutData(-1, -1, new Margins(0, 0,
//				0, 30)));
//
////		searchButton = new TextButton(strings.searchButton());
////		searchButton.addSelectHandler(new SelectHandler() {
////
////			@Override
////			public void onSelect(SelectEvent event) {
////				searchCriteria = "";
////				if (!grid.isVisible()) {
//////					grid.setVisible(true);
//////					toolBar.setVisible(true);
////					container.forceLayout();
////				}
////				loader.load();
////			}
////		});
//
////		cont.add(searchButton, new HorizontalLayoutData(-1, -1, new Margins(0,
////				0, 0, 10)));
//
//		return searchArea;
//
//	}
	
	@UiHandler("searchButton")
	public void onSearchButton(SelectEvent event) {
		searchCriteria = "";
		if (!grid.isVisible()) {
//			container.forceLayout();
		}
		loader.load();
	}

	@UiHandler("clearButton")
	public void onClearButton(SelectEvent event) {
		searchCriteria = "";
		searchGrp.clear();
		searchAuto.clear();
		searchEngine.clear();
		loader.load();
	}

	@Override
	public HasSelectHandlers getEdit() {
		return editButton;
	}

	@Override
	public Grid<PartitemProxy> getGrid() {
		return grid;
	}

	@Override
	public HasSelectHandlers getAdd() {
		return addButton;
	}

	@Override
	public HasSelectHandlers getDelete() {
		return deleteButton;
	}

	@Override
	public void mask(boolean show) {
		if (show) {
//			container.mask();
		} else {
//			container.unmask();
		}
	}

	@Override
	public Widget asWidget() {
		return root;
	}
	
	
	public void filterEngines( PartgroupProxy grpItem, AutoProxy autoItem ) {
		long grp = grpItem != null ? grpItem.getId() : 0;
		long auto = autoItem != null ? autoItem.getId() : 0;
		searchEngine.getStore().clear();
		List<EngineProxy> fullList = Utils.getEngineList();
//		TreeMap<String, EngineProxy> eList  = new TreeMap<String, EngineProxy>();
		ArrayList<String> eList = new ArrayList<String>();
		if ( fullList != null ) {
//			engineStore.addAll(fullList);
			for (EngineProxy engine : fullList) {
				if (grp > 0 && grp != engine.getPartgroup()) {
					continue;
				}
				if (auto > 0 && auto != engine.getAuto()) {
					continue;
				}
				if (!eList.contains(engine.getName())) {
					eList.add(engine.getName());					
				}
//				eList.put(engine.getName(), engine);
////				engineStore.add(engine);
			}
		}
//		Log.debug("put to engine list [" + eList.values().size() + "] values");
		Log.debug("put to engine list [" + eList.size() + "] values");
		searchEngine.add(eList);
	}
	
	

}
